package com.iflytek.iot.quartz.factory;


import com.iflytek.iot.quartz.JobResult;
import com.iflytek.iot.quartz.ScheduleJob;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 动态定时任务
 * Created by yu on 2018/12/26.
 */
@Configuration
public class DynamicJobFactory {

    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicJobFactory.class);


    @Resource
    private Scheduler scheduler;

    /**
     * 添加job
     *
     * @param scheduleJob 任务参数
     * @param jobDataMap  任务的其他数据
     * @throws Exception
     */
    public JobResult addJob(ScheduleJob scheduleJob, JobDataMap jobDataMap) throws Exception {
        JobDetail jobDetail;
        try {
            jobDetail = createJobDetail(scheduleJob, jobDataMap);
        } catch (Exception e) {
            LOGGER.error("触发器：{} 不存在", scheduleJob.getClassName());
            e.printStackTrace();
            return JobResult.fail("触发器:" + scheduleJob.getClassName() + "不存在");
        }
        CronTriggerImpl cronTrigger = new CronTriggerImpl();
        cronTrigger.setName("JobTrigger:" + scheduleJob.getUniqueKey());
        cronTrigger.setCronExpression(scheduleJob.getCronExpression());
        JobKey jobKey = new JobKey(scheduleJob.getUniqueKey(), Scheduler.DEFAULT_GROUP);
        if (!scheduler.checkExists(jobKey)) {
            scheduler.scheduleJob(jobDetail, cronTrigger);
            return JobResult.ok("添加启动任务成功");
        } else {
            return JobResult.fail("该任务已经启动！");
        }
    }

    /**
     * 启动一个立即性任务
     *
     * @param scheduleJob 任务job
     * @param jobDataMap  job参数
     * @return
     * @throws Exception
     */
    public JobResult addNowRunJob(ScheduleJob scheduleJob, JobDataMap jobDataMap) throws Exception {
        JobDetail jobDetail;
        try {
            jobDetail = createJobDetail(scheduleJob, jobDataMap);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("触发器：{} 不存在", scheduleJob.getClassName());
            return JobResult.fail("触发器:" + scheduleJob.getClassName() + "不存在");
        }
        SimpleScheduleBuilder builder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)
                .withRepeatCount(0);
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(scheduleJob.getUniqueKey(), Scheduler.DEFAULT_GROUP).startNow()
                .withSchedule(builder).build();
        JobKey jobKey = new JobKey(scheduleJob.getUniqueKey(), Scheduler.DEFAULT_GROUP);
        if (!scheduler.checkExists(jobKey)) {
            scheduler.scheduleJob(jobDetail, trigger);
            return JobResult.ok("添加启动任务成功");
        } else {
            return JobResult.ok("该任务已经启动！");
        }
    }

    /**
     * 暂停job
     *
     * @param className 类名
     * @throws Exception
     */
    public void pause(String className) throws SchedulerException {
        JobKey jobKey = new JobKey(className, Scheduler.DEFAULT_GROUP);
        scheduler.pauseJob(jobKey);
    }

    /**
     * 重启job
     *
     * @param className
     * @throws Exception
     */
    public void resume(String className) throws SchedulerException {
        JobKey jobKey = new JobKey(className, Scheduler.DEFAULT_GROUP);
        scheduler.resumeJob(jobKey);
    }

    /**
     * 停止job
     *
     * @param className
     * @throws Exception
     */
    public void stop(String className) throws SchedulerException {
        JobKey jobKey = new JobKey(className, Scheduler.DEFAULT_GROUP);
        scheduler.deleteJob(jobKey);
    }

    /**
     * 修改任务后可以动态启动
     *
     * @param className
     * @param cronExpression
     * @throws Exception
     */
    public void updateJobTime(String className, String cronExpression) throws Exception {
        TriggerKey triggerKey = new TriggerKey("JobTrigger:" + className, Scheduler.DEFAULT_GROUP);
        CronTriggerImpl trigger = (CronTriggerImpl) scheduler.getTrigger(triggerKey);
        if (trigger == null) {
            return;
        }
        String oldTime = trigger.getCronExpression();
        if (!oldTime.equalsIgnoreCase(cronExpression)) {
            trigger.setCronExpression(cronExpression);
            scheduler.rescheduleJob(triggerKey, trigger);
        }
    }


    /**
     * 获取任务的状态
     *
     * @param className
     * @return
     * @throws SchedulerException
     */
    public List<ScheduleJob> getJobDetail(String className) throws SchedulerException {
        JobKey jobKey = new JobKey(className, Scheduler.DEFAULT_GROUP);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if (Objects.isNull(jobDetail)) {
            return new ArrayList<>(0);
        }
        List<ScheduleJob> jobList = new ArrayList<>();
        addToJobList(jobList, jobKey, jobDetail);
        return jobList;
    }

    /**
     * 获取任务列表
     *
     * @return
     * @throws SchedulerException
     */
    public List<ScheduleJob> getJobList() throws SchedulerException {
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
        List<ScheduleJob> jobList = new ArrayList<>();
        for (JobKey jobKey : jobKeys) {
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            addToJobList(jobList, jobKey, jobDetail);
        }
        return jobList;
    }


    /**
     * 获取正在执行的任务
     *
     * @return
     * @throws SchedulerException
     */
    public List<ScheduleJob> getCurrentlyJob() throws SchedulerException {
        List<ScheduleJob> jobList = new ArrayList<>();
        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
        for (JobExecutionContext executingJob : executingJobs) {
            JobDetail jobDetail = executingJob.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            Trigger trigger = executingJob.getTrigger();
            ScheduleJob job = createScheduleJob(jobKey, trigger);
            jobList.add(job);
        }
        return jobList;
    }


    /**
     * 启动所有的任务
     *
     * @throws SchedulerException
     */
    public void startJobs() throws SchedulerException {
        scheduler.start();
    }

    /**
     * shutdown所有的任务
     *
     * @throws SchedulerException
     */
    public void shutdownJobs() throws SchedulerException {
        if (!scheduler.isShutdown()) {
            scheduler.shutdown();
        }
    }

    /**
     * 创建JobDetail
     *
     * @param scheduleJob
     * @param jobDataMap
     * @return
     * @throws Exception
     */
    private JobDetail createJobDetail(ScheduleJob scheduleJob, JobDataMap jobDataMap) throws Exception {
        Class clazz = scheduleJob.getJobClass();
        if (null == clazz) {
            clazz = Class.forName(scheduleJob.getClassName());
            scheduleJob.setJobClass(clazz);
        }
        if (Objects.isNull(jobDataMap)) {
            jobDataMap = new JobDataMap();
        }
        JobDetail jobDetail = JobBuilder.newJob(clazz)
                .withIdentity(scheduleJob.getUniqueKey(), Scheduler.DEFAULT_GROUP)
                .withDescription(scheduleJob.getDesc())
                .setJobData(jobDataMap)
                .build();
        return jobDetail;
    }

    /**
     * 添加job到 job list中
     *
     * @param jobList   List<ScheduleJob>
     * @param jobKey    JobKey
     * @param jobDetail JobDetail
     * @throws SchedulerException
     */
    private void addToJobList(List<ScheduleJob> jobList, JobKey jobKey, JobDetail jobDetail) throws SchedulerException {
        List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobDetail.getKey());
        for (Trigger trigger : triggers) {
            ScheduleJob scheduleJob = createScheduleJob(jobKey, trigger);
            jobList.add(scheduleJob);
        }
    }

    /**
     * 创建ScheduleJob
     *
     * @param jobKey  JobKey
     * @param trigger Trigger
     * @return
     * @throws SchedulerException
     */
    private ScheduleJob createScheduleJob(JobKey jobKey, Trigger trigger) throws SchedulerException {
        ScheduleJob scheduleJob = new ScheduleJob();
        scheduleJob.setName(jobKey.getName());
        scheduleJob.setGroupName(jobKey.getGroup());
        scheduleJob.setDesc("JobTrigger:" + trigger.getKey());
        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
        scheduleJob.setStatus(triggerState.name());
        if (trigger instanceof CronTrigger) {
            CronTrigger cronTrigger = (CronTrigger) trigger;
            String cronExpression = cronTrigger.getCronExpression();
            scheduleJob.setCronExpression(cronExpression);
        }
        return scheduleJob;
    }

}
